package core

import (
	"bytes"
	"fmt"
	"sort"
	"strings"
)

type BaseData struct {
	Name  string //名称
	Bonus int    //番数
}

type Reward struct {
	Data BaseData
	Flag int //标识
}

type Paixing struct {
	Point      int                 //底分
	RewardList map[string]Reward   //牌型列表
	GainList   map[string]BaseData //加倍列表
}

type PaixingResult struct {
	RewardName string
	Bonus      int
	Score      int
	Gen        int
}

var px *Paixing

func init() {
	px = &Paixing{}
	px.Point = 1
	// 胡牌牌型 ， d：对 g：杠 p：碰 s：顺， key:牌型  ，name:胡型名称，bonus：番数
	// flag：胡型有额外特殊奖励条件 0.无（七对除外） 1.带幺九 2.金钩钓 3.带幺九+金钩钓 4.不计杠
	px.RewardList = map[string]Reward{
		"ddddddd": {Data: BaseData{Name: "七对", Bonus: 4}, Flag: 4},
		"dgggg":   {Data: BaseData{Name: "十八罗汉", Bonus: 64}, Flag: 4},
		"dgggp":   {Data: BaseData{Name: "碰碰胡", Bonus: 2}, Flag: 2},
		"dgggs":   {Data: BaseData{Name: "平胡", Bonus: 1}, Flag: 0},
		"dggpp":   {Data: BaseData{Name: "碰碰胡", Bonus: 2}, Flag: 2},
		"dggps":   {Data: BaseData{Name: "平胡", Bonus: 1}, Flag: 0},
		"dggss":   {Data: BaseData{Name: "平胡", Bonus: 1}, Flag: 0},
		"dgppp":   {Data: BaseData{Name: "碰碰胡", Bonus: 2}, Flag: 2},
		"dgpps":   {Data: BaseData{Name: "平胡", Bonus: 1}, Flag: 0},
		"dgpss":   {Data: BaseData{Name: "平胡", Bonus: 1}, Flag: 0},
		"dgsss":   {Data: BaseData{Name: "平胡", Bonus: 1}, Flag: 0},
		"dpppp":   {Data: BaseData{Name: "碰碰胡", Bonus: 2}, Flag: 3},
		"dppps":   {Data: BaseData{Name: "平胡", Bonus: 1}, Flag: 1},
		"dppss":   {Data: BaseData{Name: "平胡", Bonus: 1}, Flag: 1},
		"dpsss":   {Data: BaseData{Name: "平胡", Bonus: 1}, Flag: 1},
		"dssss":   {Data: BaseData{Name: "平胡", Bonus: 1}, Flag: 1},
	}

	px.GainList = map[string]BaseData{
		"qys":  {Name: "清一色", Bonus: 4}, //清一色 x4番
		"jgd":  {Name: "金钩钓", Bonus: 4}, //金钩钓 x4番
		"dyj":  {Name: "带幺九", Bonus: 4}, //带幺九 x4番
		"jd":   {Name: "将对", Bonus: 8},  //将对 x4番
		"long": {Name: "龙", Bonus: 2},   //龙 x2番
	}
}

func GetPaixing() *Paixing {
	return px
}

//检查牌型
func (p *Paixing) CheckPaixing(cards, peng, gang []int, huRes [][]int) (result *PaixingResult, msg string) {
	huArr := p.CombineHuResAndPG(huRes, peng, gang)
	fmt.Printf("huArr : %v \n", huArr)
	colors := p.BindColor(huArr)
	fmt.Printf("colors : %v \n", colors)

	pxType, genNum := p.BindType(huArr, gang)
	fmt.Printf("pxType : %v  , genNum : %v \n", pxType, genNum)
	if len(colors) > 2 {
		return nil, "胡牌失败，手牌花色大于2种！"
	}
	if _, ok := px.RewardList[pxType]; !ok {
		return nil, "胡牌失败，数据错误，没有该胡型！"
	}

	//---------------------- 结算 start -----------------------------

	rewardArr := p.BindReward(pxType, huArr, colors, peng, gang)
	fmt.Printf("rewardArr : %v \n", rewardArr)
	gangNum := len(gang)
	//龙七对单独处理，根数还需减扣1
	if strings.Contains(pxType, "ddddddd") {
		countValues := mj.arrayCountValues(cards)
		for _, v := range countValues {
			if v == 4 {
				genNum += 1
			}
		}
		if genNum > 0 {
			rewardArr = append(rewardArr, p.GainList["long"])
			genNum -= 1
		}
	}
	if strings.Contains(pxType, "dgggg") {
		genNum = 0
	}
	// 根奖励 x2 番
	genBonus := 1
	if genNum > 0 {
		genBonus *= 2
	}
	// 杠奖励 x2 番
	gangBonus := 1
	if gangNum > 0 {
		gangBonus *= 2
	}
	// 总番数
	totalBonus := genBonus * gangBonus
	// 所有胡型番数相乘
	for _, v := range rewardArr {
		totalBonus *= v.Bonus
	}
	// 积分 (底金 x 总番数 )
	points := p.Point * totalBonus
	totalRewardName := p.BindTotalRewardName(rewardArr)

	result = &PaixingResult{}
	result.RewardName = totalRewardName
	result.Bonus = totalBonus
	result.Score = points
	result.Gen = genNum
	return result, ""
}

//绑定花色
func (p *Paixing) BindColor(huArr [][]int) []int {
	colors := make([]int, 0)
	for _, arr := range huArr {
		for _, card := range arr {
			if card >= 1 && card <= 9 {
				colors = append(colors, 1) //万
			}
			if card >= 11 && card <= 19 {
				colors = append(colors, 2) //筒
			}
			if card >= 21 && card <= 29 {
				colors = append(colors, 3) //条
			}
		}
	}
	return p.ArrayUnique(colors)
}

//绑定牌型类别
func (p *Paixing) BindType(huArr [][]int, gang []int) (pxType string, genNum int) {
	pxType = ""
	genNum = 0
	tpArr := make([]string, 0)
	for _, v := range huArr {
		num := len(v)
		if num == 2 {
			tpArr = append(tpArr, "d") //对子
		}
		if num == 3 {
			if v[0] == v[1] {
				tpArr = append(tpArr, "p") //刻子
			} else {
				tpArr = append(tpArr, "s") //顺子
			}
		}
		if num == 4 {
			tpArr = append(tpArr, "g")    //大刻子
			flag := p.InArray(v[0], gang) //查找手牌中的暗杠
			if flag {
				genNum += 1
			}
		}
	}
	sort.Strings(tpArr)
	var buffer bytes.Buffer
	for _, v := range tpArr {
		buffer.WriteString(v)
	}
	pxType = buffer.String()
	return pxType, genNum
}

//绑定胡型奖励信息：【胡型名称，番数】
func (p *Paixing) BindReward(typeName string, huArr [][]int, colors, peng, gang []int) (rewardArr []BaseData) {
	// 基础胡
	rewardArr = append(rewardArr, p.RewardList[typeName].Data)
	//清一色
	qys := true
	if len(colors) > 1 {
		qys = false
	}
	if qys {
		rewardArr = append(rewardArr, p.GainList["qys"])
	}
	flag := p.RewardList[typeName].Flag
	// 带幺九
	if p.InArray(flag, []int{1, 3}) {
		if p.CheckDyj(huArr) {
			rewardArr = rewardArr[1:] // 删除开头1个元素，以后面的牌型名称替代首个牌型名字
			temArr := make([]BaseData, 0)
			temArr = append(temArr, p.GainList["dyj"])
			temArr = append(temArr, rewardArr...)
			rewardArr = temArr
		}
	}
	// 金钩钓 、将对
	if p.InArray(flag, []int{2, 3}) {
		if p.CheckJgd(peng, gang) {
			rewardArr = rewardArr[1:] // 删除开头1个元素，以后面的牌型名称替代首个牌型名字
			temArr := make([]BaseData, 0)
			temArr = append(temArr, p.GainList["jgd"])
			temArr = append(temArr, rewardArr...)
			rewardArr = temArr
		}
		if p.CheckJd(huArr) {
			rewardArr = append(rewardArr, p.GainList["jd"])
		}
	}
	return rewardArr
}

func (p *Paixing) BindTotalRewardName(rewardArr []BaseData) string {
	num := len(rewardArr)
	if num == 1 {
		return rewardArr[0].Name
	}
	firstName := rewardArr[1].Name
	secondName := ""
	if num == 3 {
		secondName = rewardArr[2].Name
	}
	thirdName := ""
	if !strings.Contains(rewardArr[0].Name, "平胡") {
		thirdName = rewardArr[0].Name
	}
	return firstName + secondName + thirdName
}

//检查花色，有定缺的花色，就不能胡牌
func (p *Paixing) CheckColor(cards []int, colorNum int) bool {
	min, max := 0, 0
	switch colorNum {
	case 1:
		min, max = 1, 9
	case 2:
		min, max = 11, 19
	case 3:
		min, max = 21, 29
	default:
		return false
	}
	for _, card := range cards {
		if card >= min && card <= max {
			return false
		}
	}
	return true
}

//校验牌数,不等于14则不能虎牌（杠牌也按3张算，胡牌总牌数就固定是14）
func (p *Paixing) CheckCardNum(cards, peng, gang []int) bool {
	totalNum := len(cards) + len(peng)*3 + len(gang)*3
	if totalNum != 14 {
		return false
	}
	return true
}

//校验将对，由二、五、八组成的碰碰胡
func (p *Paixing) CheckJd(huArr [][]int) bool {
	flag := true
	for _, arr := range huArr {
		for _, v := range arr {
			if !p.InArray(v, []int{2, 5, 8, 12, 15, 18, 22, 25, 28}) {
				flag = false
				break
			}
		}
	}
	return flag
}

//校验带幺九，顺子，刻子和将牌都含一或九
func (p *Paixing) CheckDyj(huArr [][]int) bool {
	num := 0
	for _, arr := range huArr {
		for _, v := range arr {
			if !p.InArray(v, []int{1, 9, 11, 19, 21, 29}) {
				num += 1
				break
			}
		}
	}
	if num == 5 {
		return true
	}
	return false
}

//校验金钩钓，胡牌时其他都被碰牌，杠牌
func (p *Paixing) CheckJgd(peng, gang []int) bool {
	totalNum := len(peng) + len(gang)
	if totalNum == 4 {
		return true
	}
	return false
}

func (p *Paixing) ArrayUnique(data []int) []int {
	result := make([]int, 0, len(data))
	temp := map[int]int{}
	for _, item := range data {
		if _, ok := temp[item]; !ok { //如果字典中找不到元素，ok=false，!ok为true，就往切片中append元素。
			temp[item] = 0
			result = append(result, item)
		}
	}
	return result
}

func (p *Paixing) InArray(num int, data []int) bool {
	for _, v := range data {
		if num == v {
			return false
		}
	}
	return true
}

func (p *Paixing) CombineHuResAndPG(huRes [][]int, peng, gang []int) (huArr [][]int) {
	huArr = append(huArr, huRes...)
	if len(peng) > 0 {
		for _, card := range peng {
			huArr = append(huArr, []int{card, card, card})
		}
	}
	if len(gang) > 0 {
		for _, card := range gang {
			huArr = append(huArr, []int{card, card, card, card})
		}
	}
	return huArr
}
